#include <benchmark/benchmark.h>
#include <cstdint>
#include <functional>
#include <memory>
#include <vector>

namespace {
inline void simulate_work() {
    static std::uint64_t value = 0;
    value = value * 1103515245ULL + 12345ULL;
    benchmark::DoNotOptimize(value);
    benchmark::ClobberMemory();
}
} // namespace

// === 虚函数实现 ===
class Base {
public:
    virtual void doWork() const {
        simulate_work();
    }
    virtual ~Base() = default;
};

class Derived : public Base {
public:
    void doWork() const override {
        simulate_work();
    }
};

// 虚函数基准测试
static void BM_VirtualFunction(benchmark::State& state) {
    const int N = state.range(0);
    std::vector<std::unique_ptr<Base>> objects;
    objects.reserve(N);

    for (int i = 0; i < N; ++i) {
        objects.emplace_back(std::make_unique<Derived>());
    }

    for (auto _ : state) {
        for (const auto& obj : objects) {
            benchmark::DoNotOptimize(obj);
            obj->doWork();
        }
    }

    state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * N);
}
BENCHMARK(BM_VirtualFunction)->Arg(10'000'000);

// === 组合 + 虚函数实现 ===
class Advanced : public Base {
private:
    Base base; // 组合基础类
public:
    void doWork() const override {
        base.doWork();
    }
};

// 组合 + 虚函数基准测试
static void BM_CompositionVirtualFunction(benchmark::State& state) {
    const int N = state.range(0);
    std::vector<std::unique_ptr<Base>> objects;
    objects.reserve(N);

    for (int i = 0; i < N; ++i) {
        objects.emplace_back(std::make_unique<Advanced>());
    }

    for (auto _ : state) {
        for (const auto& obj : objects) {
            benchmark::DoNotOptimize(obj);
            obj->doWork();
        }
    }

    state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * N);
}
BENCHMARK(BM_CompositionVirtualFunction)->Arg(10'000'000);

// === 模板（静态分派）实现 ===
class BaseTemplate {
public:
    void doWork() const {
        simulate_work();
    }
};

template <typename T>
class AdvancedTemplate {
private:
    T base; // 组合基础类
public:
    void doWork() const {
        base.doWork();
    }
};

// 模板基准测试
static void BM_TemplateStaticDispatch(benchmark::State& state) {
    const int N = state.range(0);
    AdvancedTemplate<BaseTemplate> advanced;

    for (auto _ : state) {
        for (int i = 0; i < N; ++i) {
            benchmark::DoNotOptimize(i);
            advanced.doWork();
        }
    }

    state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * N);
}
BENCHMARK(BM_TemplateStaticDispatch)->Arg(10'000'000);

// === std::function 实现 ===
class AdvancedFunction {
private:
    BaseTemplate base; // 组合基础类
public:
    void doWork() const {
        base.doWork();
    }

    std::function<void()> getWorker() const {
        return [this]() { this->doWork(); };
    }
};

// std::function 基准测试
static void BM_StdFunction(benchmark::State& state) {
    const int N = state.range(0);
    std::vector<std::function<void()>> workers;
    workers.reserve(N);

    AdvancedFunction advanced;
    for (int i = 0; i < N; ++i) {
        workers.emplace_back(advanced.getWorker());
    }

    for (auto _ : state) {
        for (const auto& worker : workers) {
            benchmark::DoNotOptimize(worker);
            worker();
        }
    }

    state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * N);
}
BENCHMARK(BM_StdFunction)->Arg(10'000'000);

// === CRTP 实现 ===
template <typename Derived>
class CRTPBase {
public:
    void doWork() const {
        static_cast<const Derived*>(this)->doWorkImpl();
    }
};

class CRTPDerived : public CRTPBase<CRTPDerived> {
public:
    void doWorkImpl() const {
        simulate_work();
    }
};

// CRTP 基准测试
static void BM_CRTP(benchmark::State& state) {
    const int N = state.range(0);
    CRTPDerived obj;

    for (auto _ : state) {
        for (int i = 0; i < N; ++i) {
            benchmark::DoNotOptimize(i);
            obj.doWork();
        }
    }

    state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * N);
}
BENCHMARK(BM_CRTP)->Arg(10'000'000);

BENCHMARK_MAIN();   